// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IMAGE_H_
#define IMAGE_H_

#include <memory>
#include "compat.h"

template <typename T>
class ImageTmpl {
 public:
  enum Colorspace {
    COLORSPACE_NONE = 0,
    GRAYSCALE,
    GRAYSCALE_ALPHA,
    RGB,
    RGBA
  };

  ImageTmpl() : width_(0), height_(0), channels_(0), colorspace_(COLORSPACE_NONE) {}

  ~ImageTmpl() {}

  void Resize(int width, int height, Colorspace colorspace) {
    width_ = width;
    height_ = height;
    colorspace_ = colorspace;
    channels_ = ColorspaceToChannels(colorspace);
    pixels_.reset(new T[width_ * height_ * channels_]);
  }

  void CopyFrom(const ImageTmpl& copy) {
    Resize(copy.width(), copy.height(), copy.colorspace());
    int count = width_ * height_ * channels_;
    std::copy(copy.pixel_data(), copy.pixel_data() + count, mutable_pixel_data());
  }

  bool Equals(const ImageTmpl& other) const {
    if (width() != other.width() ||
        height() != other.height() ||
        colorspace() != other.colorspace()) {
      return false;
    }
    int count = width_ * height_ * channels_;
    for (int i = 0; i < count; ++i) {
      if (pixels_[i] != other.pixels_[i]) {
        return false;
      }
    }
    return true;
  }

  int width() const { return width_; }
  int height() const { return height_; }
  int channels() const { return channels_; }
  Colorspace colorspace() const { return colorspace_; }

  const T* pixel_data() const { return pixels_.get(); }
  T* mutable_pixel_data() { return pixels_.get(); }

  T GetValue(int x, int y, int channel) const {
    return pixels_[(y * width_ + x) * channels_ + channel];
  }

  void SetValue(int x, int y, int channel, T value) {
    pixels_[(y * width_ + x) * channels_ + channel] = value;
  }

 private:
  int ColorspaceToChannels(Colorspace colorspace) {
    switch(colorspace) {
      case GRAYSCALE: return 1; break;
      case GRAYSCALE_ALPHA: return 2; break;
      case RGB: return 3; break;
      case RGBA: return 4; break;
      default: CHECK(false); break;
    }
  }

  int width_;
  int height_;
  int channels_;
  Colorspace colorspace_;
  std::unique_ptr<T[]> pixels_;

  // Disallow copy and assignment.
  ImageTmpl(const ImageTmpl& copy);
  ImageTmpl& operator=(const ImageTmpl& copy);
};

typedef ImageTmpl<uint8> Image;
typedef ImageTmpl<float> FloatImage;

#endif  // IMAGE_H_
